import 'dart:collection';

import 'package:amoy_ticket/utils/router/log_util.dart';
import 'package:dio/dio.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:fluttertoast/fluttertoast.dart';

import '../net_util/net_utils.dart';

class HttpManager {
  static HttpManager _instance = HttpManager._internal();
  Dio _dio = Dio();

  static const CODE_SUCCESS = 200;
  static const CODE_TIME_OUT = -1;

  factory HttpManager() => _instance;

  ///通用全局单例，第一次使用时初始化
  HttpManager._internal() {
    _dio = Dio();

    _dio.interceptors.add(HeaderInterceptors());

    _dio.interceptors.add(LogInterceptor());

//      _dio.interceptors.add(new PrettyDioLogger());
    // _dio.interceptors.add(new ResponseInterceptors());
  }

  static HttpManager getInstance({String? baseUrl}) {
    if (baseUrl == null) {
      return _instance._normal();
    } else {
      return _instance._baseUrl(baseUrl);
    }
  }

  //用于指定特定域名
  HttpManager _baseUrl(String baseUrl) {
    _dio.options.baseUrl = baseUrl;

    return this;
  }

  //一般请求，默认域名
  HttpManager _normal() {
    if (_dio.options.baseUrl != Address.BASE_URL) {
      _dio.options.baseUrl = Address.BASE_URL;
    }

    return this;
  }

  ///通用的GET请求
  get(api, {params, withLoading = true}) async {
    if (withLoading) {
      LoadingUtils.show();
    }
    Response response;
    try {
      response = await _dio.get(api, queryParameters: params);
      if (withLoading) {
        LoadingUtils.dismiss();
      }
    } on DioError catch (e) {
      if (withLoading) {
        LoadingUtils.dismiss();
      }
      return resultError(e);
    }

    if (response.data is DioError) {
      return resultError(response.data['code']);
    }

    return response.data;
  }

  ///通用的POST请求
  post(api, {params, withLoading = true}) async {
    if (withLoading) {
      LoadingUtils.show();
    }

    Response response;

    try {
      response = await _dio.post(api, data: params);
      if (withLoading) {
        LoadingUtils.dismiss();
      }
    } on DioError catch (e) {
      if (withLoading) {
        LoadingUtils.dismiss();
      }
      return resultError(e);
    }

    if (response.data is DioError) {
      return resultError(response.data['code']);
    }

    return response.data;
  }
}

ResultData resultError(DioError e) {
  Response? errorResponse;
  if (e.response != null) {
    errorResponse = e.response;
  } else {
    errorResponse =
        Response(statusCode: 666, requestOptions: RequestOptions(path: ''));
  }
  if (e.type == DioError.connectionTimeout ||
      e.type == DioError.receiveTimeout) {
    errorResponse?.statusCode = 200;
  }
  return new ResultData(
      errorResponse?.statusMessage, false, errorResponse?.statusCode);
}

/// 响应基类
class ResultData {
  var data;
  bool isSuccess;
  int? code;
  var headers;

  ResultData(this.data, this.isSuccess, this.code, {this.headers});
}

///Api的封装  请求的集中管理
class Api {
  ///示例请求
  static request(String param) {
    var params = DataHelper.getBaseMap();
    params['param'] = param;
    return HttpManager.getInstance().get(Address.TEST_API, params: params);
  }
}

/// 公共参数和加密等
class DataHelper {
  static SplayTreeMap getBaseMap() {
    var map = new SplayTreeMap<String, dynamic>();
    map["platform"] = 'platform';
    map["system"] = 'system';
    map["channel"] = 'channel';
    map["time"] = new DateTime.now().millisecondsSinceEpoch.toString();
    return map;
  }
}

/// 方便地址管理
class Address {
  static const String TEST_API = "test_api";
  static const String BASE_URL = 'https://restapi.amap.com';
}

/// 响应拦截器  过滤正确的响应数据，对数据进行初步封装
class ResponseInterceptors extends InterceptorsWrapper {
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    RequestOptions option = response.requestOptions;
    try {
      if (option.contentType != null) {
        return handler.next(response);
      }

      ///一般只需要处理200的情况，300、400、500保留错误信息
      if (response.statusCode == 200 || response.statusCode == 201) {
        int code = response.data["code"];
        if (code == 0) {
          // return ResultData(response.data, true, Code.SUCCESS,
          //     headers: response.headers);
        } else if (code == 100006 || code == 100007) {
        } else {
          Fluttertoast.showToast(msg: response.data["msg"]);
          // return ResultData(response.data, false, 1, headers: response.headers);
        }
      }
    } catch (e) {
      print(e.toString() + option.path);

      // return ResultData(response.data, false, response.statusCode,
      //     headers: response.headers);
    }

    // return ResultData(response.data, false, response.statusCode,
    //     headers: response.headers);
  }
}

///日志拦截器   打印请求参数和返回参数
class LogInterceptor extends InterceptorsWrapper {
  @override
  Future onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    String requestStr = "==================== REQUEST ====================\n"
        "- URL: ${options.baseUrl + options.path}\n\n"
        "- method: ${options.method}\n";

    requestStr += "- HEADER:${options.headers.mapToStructureString()}\n\n";

    requestStr += "- baseUrl:--${options.baseUrl}\n\n";

    final data = options.data;
    if (data != null) {
      if (data is Map)
        requestStr += "- BODY:\n${data.mapToStructureString()}\n";
      else if (data is FormData) {
        final formDataMap = Map()
          ..addEntries(data.fields)
          ..addEntries(data.files);
        requestStr += "- BODY:\n${formDataMap.mapToStructureString()}\n";
      } else
        requestStr += "- BODY:\n${data.toString()}\n";
    }
    LogUtil.get().d(requestStr);
    return handler.next(options);
  }

  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) async {
    String errorStr = "\n==================== RESPONSE ====================\n"
        "- URL:\n${err.requestOptions.baseUrl + err.requestOptions.path}\n"
        "- METHOD: ${err.requestOptions.method}\n";

    errorStr +=
        "- HEADER:\n${err.response?.headers.map.mapToStructureString()}\n";
    if (err.response != null && err.response?.data != null) {
      print('╔ ${err.type.toString()}');
      errorStr += "- ERROR:\n${_parseResponse(err.response)}\n";
    } else {
      errorStr += "- ERRORTYPE: ${err.type}\n";
      errorStr += "- MSG: ${err.message}\n";
    }

    LogUtil.get().d(errorStr);
    return handler.next(err);
  }

  @override
  Future onResponse(
      Response response, ResponseInterceptorHandler handler) async {
    String responseStr = "==================== RESPONSE ====================\n"
        "- URL: ${response.requestOptions.uri}\n";
    responseStr += "- HEADER: {";
    response.headers
        .forEach((key, list) => responseStr += "\n " + "\"$key\" : \"$list\",");
    responseStr += "\n}\n";
    responseStr += "- STATUS: ${response.statusCode}\n\n";

    if (response.data != null) {
      responseStr += "- BODY:\n ${_parseResponse(response)}\n";
    }
    LogUtil.get().d(responseStr);
    return handler.next(response);
  }

  void printWrapped(String text) {
    final pattern = new RegExp('.{1,800}'); // 800 is the size of each chunk
    pattern.allMatches(text).forEach((match) => print(match.group(0)));
  }

  String _parseResponse(Response? response) {
    String responseStr = "";
    var data = response?.data;
    if (data is Map)
      responseStr += data.mapToStructureString();
    else if (data is List)
      responseStr += data.listToStructureString();
    else
      responseStr += response!.data.toString();

    return responseStr;
  }
}

extension Map2StringEx on Map {
  String mapToStructureString({int indentation = 2}) {
    String result = "";
    String indentationStr = " " * indentation;
    if (true) {
      result += "{";
      this.forEach((key, value) {
        if (value is Map) {
          var temp = value.mapToStructureString(indentation: indentation + 2);
          result += "\n$indentationStr" + "\"$key\" : $temp,";
        } else if (value is List) {
          result += "\n$indentationStr" +
              "\"$key\" : ${value.listToStructureString(indentation: indentation + 2)},";
        } else {
          result += "\n$indentationStr" + "\"$key\" : \"$value\",";
        }
      });
      result = result.substring(0, result.length - 1);
      result += indentation == 2 ? "\n}" : "\n${" " * (indentation - 1)}}";
    }

    return result;
  }
}

extension List2StringEx on List {
  String listToStructureString({int indentation = 2}) {
    String result = "";
    String indentationStr = " " * indentation;
    if (true) {
      result += "$indentationStr[";
      this.forEach((value) {
        if (value is Map) {
          var temp = value.mapToStructureString(indentation: indentation + 2);
          result += "\n$indentationStr" + "\"$temp\",";
        } else if (value is List) {
          result += value.listToStructureString(indentation: indentation + 2);
        } else {
          result += "\n$indentationStr" + "\"$value\",";
        }
      });
      result = result.substring(0, result.length - 1);
      result += "\n$indentationStr]";
    }

    return result;
  }
}

class LoadingUtils {
  static void show() {
    SmartDialog.showLoading(
      clickMaskDismiss: true,
      displayTime: Duration(seconds: 5),
    );
  }

  static void dismiss() {
    SmartDialog.dismiss();
  }
}
